#include "umRtspPack.h"
#include "umapi_libc.h"
#include "string.h"
#include "umlog.h"

#define TARGET "RTSPPACKAGE"

struct methodArray{
	UM_CHAR strMethod[20];
	RTSPCMD cmd;
};


static struct methodArray method[] = {
	{"OPTIONS",E_OPTIONS},
	{"DESCRIBE", E_DESCRIBE},
	{"GET_PARAMETER", E_GET_PARAMETER},
	{"PLAY", E_PLAY},
	{"SETUP", E_SETUP},
	{"PAUSE", E_PAUSE},
	{"TEARDOWN", E_TEARDOWN},
	{"SET_PARAMETER", E_SET_PARAMETER},
};
 
static UM_S32 decLine(UM_CHAR *line, RtspPack *pRtspPack)
{
	if(umapi_strncmp(line,"CSeq",4) == 0)
	{
		umapi_sscanf(line,"CSeq: %d",&pRtspPack->cseq);
		return UM_TRUE;
	}else if(umapi_strncmp(line, "Context-Length", 14) == 0 )
	{
		umapi_sscanf(line,"Context-Length:[^ ] %d",&pRtspPack->contextLen);
		return UM_TRUE;
	}
	else {
		UM_S32 i = 0;
		for(i =0 ;i< sizeof(method)/sizeof(struct methodArray) ;i ++)
		{
			struct methodArray *pMethod = &method[i];
			if(umapi_strncmp(line, pMethod->strMethod, umapi_strlen(pMethod->strMethod)) == 0)
			{
				UM_CHAR nBuff[100];
				umapi_sscanf(line, "%[^ ] %[^ ] %[^ ]", nBuff, pRtspPack->url, pRtspPack->version);
				pRtspPack->method = pMethod->cmd;
				return UM_TRUE;
			}
		}
	}
	return UM_FALSE;
}
UM_S32 readRtspPack(UM_HANDLE socket, RtspPack **pRtspPack)
{
	#define MAXHEADLEN (4 * 1024)
	UM_CHAR rtspHead[MAXHEADLEN];
	RtspPack *nRtspPack  =(RtspPack*)malloc(sizeof(RtspPack));
	umapi_memset(nRtspPack, 0, sizeof(RtspPack));
	
	rtspHead[0] = '\0';
	UM_S32 readIndex = 0;
	UM_S32 s32Ret = 0;
	do
	{
		if(readIndex>4)
		{
			if(rtspHead[readIndex-1] == '\n' &&
				rtspHead[readIndex-2] == '\r' &&
				rtspHead[readIndex-3] == '\n' &&
				rtspHead[readIndex-4] == '\r')
			{
				rtspHead[readIndex] = '\0';
				goto READOK;
			}
		}
		else if(readIndex == 4)
		{
			if(rtspHead[0] =='$')
			{
				UM_U8 interleaved = rtspHead[1];
				nRtspPack->contextLen = (rtspHead[2] & 0xff << 8) | rtspHead[3];
				LOGI("read rtp_over_tcp :%d, len:%d", interleaved, nRtspPack->contextLen);
				goto READOK;
			}
		}
	}while((s32Ret = umapi_socket_recv(socket, &rtspHead[readIndex++], 1, 0)) == 1 && readIndex<MAXHEADLEN);
	if(s32Ret == 0)
	{
		LOGI("readIndex:%d,rtspHead:%s", readIndex, rtspHead);
		umapi_free(nRtspPack);
		return 1;
	}
	else
	{
		LOGE("socket:%d,readIndex:%d, ret:%d, rtspHead:%s", socket, readIndex, s32Ret, rtspHead);
	}
	umapi_free(nRtspPack);
	return UM_FAILURE;
READOK:
	
	umapi_list_create(&(nRtspPack->lines.node));
	char* line = strtok( rtspHead, "\r\n"); 
	
	while( line != NULL )      
	{        
		RtspLine *rline = (RtspLine *)umapi_malloc(sizeof(RtspLine));
		rline->lineLen = umapi_strlen(line);
		rline->line = (UM_CHAR *)umapi_malloc(rline->lineLen + 1);
		umapi_sprintf(rline->line, "%s", line);
		LOGI("line:%s",line);
		if(!decLine(rline->line, nRtspPack))
		{
			umapi_list_add(&rline->node, &(nRtspPack->lines.node));
		}
		else
		{
			umapi_free(rline->line);
			umapi_free(rline);
		}
		line = strtok( NULL,"\r\n");
	}
	if(nRtspPack->contextLen >0)
	{
		nRtspPack->data = umapi_malloc(nRtspPack->contextLen + 1);
		umapi_socket_recv(socket, nRtspPack->data, nRtspPack->contextLen , 0);
		((UM_CHAR*)nRtspPack->data)[nRtspPack->contextLen] = '\0';
		
	}
	*pRtspPack = nRtspPack;
	LOGI("level");
	return UM_SUCCESS;
}
UM_VOID freeRtspPack(RtspPack *pRtspPack)
{
	if(pRtspPack->contextLen >0)
	{
		umapi_free(pRtspPack->data);
	}
	struct umapi_list_head *pos, *n;
	umapi_list_for_each_safe(pos,n, &pRtspPack->lines.node)
	{
		RtspLine *rline = umapi_list_entry(pos,RtspLine,node);
		umapi_list_del(&rline->node);
		if(rline->lineLen >0)
			umapi_free(rline->line);
		umapi_free(rline);
	}
	umapi_free(pRtspPack);
}
UM_S32 readRtspPackLine(RtspPack *pRtspPack, UM_CHAR *key, UM_CHAR **pline, UM_S32 *plen)
{
	struct umapi_list_head *pos, *n;
	umapi_list_for_each_safe(pos,n, &pRtspPack->lines.node)
	{
		RtspLine *rline = umapi_list_entry(pos, RtspLine, node);
		if(rline->lineLen >0)
		{
			UM_CHAR *pTemp = umapi_strstr(rline->line,key);
			if(pTemp && pTemp == rline->line)
			{
				*pline = rline->line;
				*plen = rline->lineLen;
				return UM_SUCCESS;
			}
		}
	}
	return UM_FAILURE;
}
UM_S32 readRtspPackContext(RtspPack *pRtspPack, UM_VOID **pContext, UM_S32 *pContextLen)
{
	*pContextLen = pRtspPack->contextLen;
	*pContext = pRtspPack->data;
	return UM_SUCCESS;
}
UM_S32 readRtspPackCseq(RtspPack *pRtspPack)
{
	return pRtspPack->cseq;
}
UM_S32 toString(RtspPack *pRtspPack, UM_CHAR *headBuff)
{
	umapi_sprintf(headBuff, "%d %s %s\r\nCseq: %d\r\nContextLength:%d\r\n",
		pRtspPack->method,
		pRtspPack->url,
		pRtspPack->version,
		pRtspPack->cseq,
		pRtspPack->contextLen);
	struct umapi_list_head *pos, *n;
	umapi_list_for_each_safe(pos,n, &pRtspPack->lines.node)
	{
		RtspLine *rline = umapi_list_entry(pos, RtspLine, node);
		if(rline->lineLen >0)
		{
			umapi_sprintf(&headBuff[umapi_strlen(headBuff)], "%s\r\n",rline->line);
		}
	}
	return UM_SUCCESS;
}
